#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
监控项对话框模块 - 用于配置监控项
"""

import logging
import json
import os
import re  # 添加正则表达式模块
from typing import Dict, List, Any, Optional, Tuple, Union
from PyQt5.QtWidgets import (
    QDialog, QVBoxLayout, QHBoxLayout, QLabel, 
    QLineEdit, QPushButton, QFormLayout, QDialogButtonBox,
    QComboBox, QSpinBox, QTabWidget, QWidget, QTextEdit,
    QCheckBox, QMessageBox, QTableWidget, QTableWidgetItem,
    QHeaderView, QFileDialog, QGroupBox, QAbstractItemView,
    QRadioButton, QButtonGroup, QProgressDialog, QGridLayout,
    QListWidget, QListWidgetItem, QSplitter, QFrame, QApplication
)
from PyQt5.QtCore import Qt, pyqtSlot, QTimer, QObject
from PyQt5.QtGui import QColor, QIntValidator, QBrush

# 尝试导入pandas
try:
    import pandas as pd
    import openpyxl
    PANDAS_AVAILABLE = True
except ImportError:
    PANDAS_AVAILABLE = False

# 设置日志
logger = logging.getLogger("zabbix_tool")

# 导入自己的模块
# 修改导入路径，使用相对导入
import sys
# 添加父目录到路径
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
from src.zabbix_api import ZabbixAPI

# 添加自定义Qt常量类
class QtConst:
    DisplayRole = 0
    UserRole = 32
    BackgroundRole = 8
    Horizontal = 1
    Vertical = 2
    NoItemFlags = 0
    ItemIsEnabled = 1
    ItemIsSelectable = 2
    WindowModal = 2
    ApplicationModal = 3

class ItemDialog(QDialog):
    """监控项配置对话框"""
    
    def __init__(self, api: ZabbixAPI, hosts: List[Dict[str, Any]], parent=None):
        """
        初始化监控项对话框
        
        Args:
            api (ZabbixAPI): Zabbix API客户端
            hosts (List[Dict[str, Any]]): 主机列表
            parent: 父窗口
        """
        super().__init__(parent)
        self.api = api
        self.hosts = hosts
        self.item_types = api.get_item_types()
        self.value_types = api.get_value_types()
        
        # 初始化主机ID到主机名的映射字典
        self.hostid_to_name = {}
        for host in hosts:
            if 'hostid' in host and 'host' in host:
                self.hostid_to_name[host['hostid']] = host['host']
        
        # 获取主机的IP地址和端口
        self.host_ips = self.get_host_ip_addresses()
        
        self.setup_ui()
    
    def get_host_ip_addresses(self):
        """获取主机的IP地址和端口"""
        host_ips = {}  # 存储主机ID到IP地址的映射
        host_ports = {}  # 存储主机ID到端口的映射
        
        try:
            # 获取所有主机ID
            hostids = [host.get('hostid') for host in self.hosts if host.get('hostid')]
            
            if not hostids:
                return host_ips
                
            logger.info(f"正在获取 {len(hostids)} 台主机的IP地址和端口...")
            
            # 使用hostinterface.get API获取主机接口
            interfaces = []
            
            try:
                # 逐个获取主机接口
                for hostid in hostids:
                    if hostid:  # 确保hostid不是None
                        host_interfaces = self.api.get_host_interfaces(str(hostid))
                        if host_interfaces:
                            interfaces.extend(host_interfaces)
                
                # 处理接口数据
                if interfaces:
                    logger.info(f"找到 {len(interfaces)} 个主机接口")
                    for interface in interfaces:
                        hostid = interface.get('hostid')
                        ip = interface.get('ip')
                        port = interface.get('port')
                        
                        if hostid:
                            if hostid not in host_ips:
                                host_ips[hostid] = []
                            if ip:
                                host_ips[hostid].append(ip)
                        
                            # 存储端口信息
                            if port:
                                if hostid not in host_ports:
                                    host_ports[hostid] = []
                                host_ports[hostid].append(port)
                                
                                # 更新主机对象的端口信息
                                for host in self.hosts:
                                    if host.get('hostid') == hostid:
                                        host['port'] = port
                                        
                                        # 标记主机类型
                                        if port == "10050":
                                            host['agent_type'] = "zabbix"
                                        elif port == "161":
                                            host['agent_type'] = "snmp"
                                        break
                    
                    logger.info(f"处理完成，为 {len(host_ips)} 台主机找到了IP地址和端口")
            except Exception as api_err:
                logger.error(f"通过API获取主机接口信息失败: {str(api_err)}")
        except Exception as e:
            logger.error(f"获取主机IP地址和端口时出错: {str(e)}")
        
        self.host_ports = host_ports  # 保存端口信息
        return host_ips
    
    def setup_ui(self):
        """设置UI界面"""
        self.setWindowTitle("创建监控项")
        self.resize(800, 600)
        self.setModal(True)
        
        # 创建主布局
        main_layout = QVBoxLayout(self)
        
        # 创建表格显示选中的主机
        host_group = QGroupBox("已选主机:")
        host_layout = QVBoxLayout(host_group)
        host_layout.setContentsMargins(5, 10, 5, 5)  # 减小边距
        
        self.host_table = QTableWidget()
        self.host_table.setEditTriggers(QAbstractItemView.NoEditTriggers)  # 设置为不可编辑
        self.host_table.setSelectionBehavior(QAbstractItemView.SelectRows)  # 设置为行选择
        self.host_table.setSelectionMode(QAbstractItemView.SingleSelection)  # 设置为单选模式
        self.host_table.setColumnCount(5)  # 5列: 主机ID, IP地址, 主机名称, 可见名称, 端口号
        self.host_table.setHorizontalHeaderLabels(["主机ID", "IP地址", "主机名称", "可见名称", "端口号"])
        self.host_table.horizontalHeader().setSectionResizeMode(0, QHeaderView.ResizeToContents)
        self.host_table.horizontalHeader().setSectionResizeMode(1, QHeaderView.ResizeToContents)
        self.host_table.horizontalHeader().setSectionResizeMode(2, QHeaderView.Stretch)
        self.host_table.horizontalHeader().setSectionResizeMode(3, QHeaderView.Stretch)
        self.host_table.horizontalHeader().setSectionResizeMode(4, QHeaderView.ResizeToContents)
        
        # 设置最小高度，增加高度与触发器对话框一致
        self.host_table.setMinimumHeight(250)  # 增加默认高度以显示更多行
        
        # 添加选择变更事件，用于检测SNMP设备
        self.host_table.itemSelectionChanged.connect(self.on_host_selection_changed)
        
        # 允许用户调整表格大小
        self.host_table.horizontalHeader().setSectionResizeMode(QHeaderView.Interactive)
        self.host_table.verticalHeader().setSectionResizeMode(QHeaderView.Interactive)
        self.host_table.setSizeAdjustPolicy(QTableWidget.AdjustToContents)
        
        # 设置表格可拉伸
        host_layout.addWidget(self.host_table)
        
        # 添加调整大小提示标签，使用HBox布局实现右对齐
        hint_layout = QHBoxLayout()
        hint_layout.addStretch()
        resize_hint = QLabel("提示：可拖动表头或表格边缘调整显示区域")
        resize_hint.setStyleSheet("color: gray; font-size: 9pt;")
        hint_layout.addWidget(resize_hint)
        host_layout.addLayout(hint_layout)
        
        # 填充主机表格
        self.host_table.setRowCount(len(self.hosts))
        
        # 预先加载所有主机的完整信息 - 构建hostid->host和name->host映射表
        self.host_info_map = {}  # 主机ID -> 完整信息
        self.name_to_host_map = {}  # 可见名称 -> 技术名称
        self.load_complete_host_info()
        
        # 存储端口信息以便后续使用
        port_161_found = False
        first_host_port = None
        
        for i, host in enumerate(self.hosts):
            hostid = host.get("hostid", "")
            
            # 主机ID
            self.host_table.setItem(i, 0, QTableWidgetItem(str(hostid)))
            
            # IP地址
            ip_text = ", ".join(self.host_ips.get(hostid, [])) if hostid in self.host_ips else "-"
            self.host_table.setItem(i, 1, QTableWidgetItem(ip_text))
            
            # 主机名称（技术名称）
            technical_name = host.get("host", "")
            # 如果在原始数据中找不到技术名称，尝试从映射表中获取
            if not technical_name and hostid in self.host_info_map:
                technical_name = self.host_info_map[hostid].get("host", "")
            
            # 如果仍然找不到，尝试从visible_name映射获取
            if not technical_name:
                visible_name = host.get("name", "")
                if visible_name in self.name_to_host_map:
                    technical_name = self.name_to_host_map[visible_name]
            
            self.host_table.setItem(i, 2, QTableWidgetItem(str(technical_name)))
            
            # 可见名称 - 优先使用从API获取的完整信息
            visible_name = ""
            if hostid in self.host_info_map:
                visible_name = self.host_info_map[hostid].get("name", "")
            
            # 如果在映射表中找不到，再使用原始数据中的name字段
            if not visible_name:
                visible_name = host.get("name", "")
                
            self.host_table.setItem(i, 3, QTableWidgetItem(str(visible_name)))
            
            # 端口号
            port_text = ""
            if hasattr(self, 'host_ports') and hostid in self.host_ports:
                port_text = ", ".join(self.host_ports.get(hostid, []))
            elif host.get("port"):
                port_text = str(host.get("port", ""))
                
            port_item = QTableWidgetItem(port_text)
            
            # 为不同类型的端口设置不同的背景色
            if port_text == "10050":
                port_item.setBackground(QColor(230, 255, 230))  # 淡绿色 - Zabbix Agent
            elif port_text == "161":
                port_item.setBackground(QColor(230, 230, 255))  # 淡蓝色 - SNMP
                port_161_found = True
            
            self.host_table.setItem(i, 4, port_item)
            
            # 记录第一个主机的端口（用于后续自动设置客户端类型）
            if i == 0 and port_text:
                first_host_port = port_text
            
            # 如果技术名称仍然为空，设置该行背景色为浅红色，提示有问题
            if not technical_name:
                for col in range(5):
                    item = self.host_table.item(i, col)
                    if item:
                        item.setBackground(QColor(255, 220, 220))
        
        # 将主机组添加到主布局，设置拉伸系数为4，与触发器对话框保持一致
        main_layout.addWidget(host_group, 4)
        
        # 创建标签页面
        tab_widget = QTabWidget()
        
        # 基本信息标签页
        basic_tab = QWidget()
        basic_layout = QFormLayout(basic_tab)
        
        # 监控项名称
        self.name_edit = QLineEdit()
        basic_layout.addRow("名称:", self.name_edit)
        
        # 键值
        self.key_edit = QLineEdit()
        self.key_edit.textChanged.connect(self.on_key_changed)
        basic_layout.addRow("键值:", self.key_edit)
        
        # 客户端类型
        self.type_combo = QComboBox()
        for type_id, type_name in self.item_types.items():
            self.type_combo.addItem(type_name, type_id)
        self.type_combo.currentIndexChanged.connect(self.on_type_changed)
        basic_layout.addRow("客户端类型:", self.type_combo)
        
        # 信息类型
        self.value_type_combo = QComboBox()
        for type_id, type_name in self.value_types.items():
            self.value_type_combo.addItem(type_name, type_id)
        basic_layout.addRow("信息类型:", self.value_type_combo)
        
        # SNMP配置区域 (只在选择SNMP类型时显示)
        self.snmp_community_label = QLabel("SNMP社区:")
        self.community_edit = QLineEdit("public")  # 默认值
        basic_layout.addRow(self.snmp_community_label, self.community_edit)
        self.snmp_community_label.setVisible(False)
        self.community_edit.setVisible(False)
        
        self.snmp_oid_label = QLabel("SNMP OID:")
        self.oid_edit = QLineEdit()
        self.oid_edit.setPlaceholderText("输入OID，例如: .1.3.6.1.2.1.1.1.0")
        basic_layout.addRow(self.snmp_oid_label, self.oid_edit)
        self.snmp_oid_label.setVisible(False)
        self.oid_edit.setVisible(False)
        
        self.port_label = QLabel("SNMP端口:")
        self.port_edit = QLineEdit("161")  # 默认SNMP端口
        basic_layout.addRow(self.port_label, self.port_edit)
        self.port_label.setVisible(False)
        self.port_edit.setVisible(False)
        
        # 创建SNMPv3配置组
        self.snmpv3_group = QGroupBox("SNMPv3配置", self)
        snmpv3_layout = QFormLayout(self.snmpv3_group)
        
        # 安全名称
        self.snmpv3_security_name_label = QLabel("安全名称:", self.snmpv3_group)
        self.snmpv3_security_name_edit = QLineEdit(self.snmpv3_group)
        snmpv3_layout.addRow(self.snmpv3_security_name_label, self.snmpv3_security_name_edit)
        
        # 安全级别
        self.snmpv3_security_level_label = QLabel("安全级别:", self.snmpv3_group)
        self.snmpv3_security_level_combo = QComboBox(self.snmpv3_group)
        self.snmpv3_security_level_combo.addItem("noAuthNoPriv (无认证无加密)", 0)
        self.snmpv3_security_level_combo.addItem("authNoPriv (认证无加密)", 1)
        self.snmpv3_security_level_combo.addItem("authPriv (认证加密)", 2)
        snmpv3_layout.addRow(self.snmpv3_security_level_label, self.snmpv3_security_level_combo)
        
        # 认证协议
        self.snmpv3_auth_protocol_label = QLabel("认证协议:", self.snmpv3_group)
        self.snmpv3_auth_protocol_combo = QComboBox(self.snmpv3_group)
        self.snmpv3_auth_protocol_combo.addItem("MD5", "md5")
        self.snmpv3_auth_protocol_combo.addItem("SHA", "sha")
        snmpv3_layout.addRow(self.snmpv3_auth_protocol_label, self.snmpv3_auth_protocol_combo)
        
        # 认证密码
        self.snmpv3_auth_passphrase_label = QLabel("认证密码:", self.snmpv3_group)
        self.snmpv3_auth_passphrase_edit = QLineEdit(self.snmpv3_group)
        self.snmpv3_auth_passphrase_edit.setEchoMode(QLineEdit.Normal)  # 使用明文显示密码
        snmpv3_layout.addRow(self.snmpv3_auth_passphrase_label, self.snmpv3_auth_passphrase_edit)
        
        # 加密协议
        self.snmpv3_priv_protocol_label = QLabel("加密协议:", self.snmpv3_group)
        self.snmpv3_priv_protocol_combo = QComboBox(self.snmpv3_group)
        self.snmpv3_priv_protocol_combo.addItem("DES", "des")
        self.snmpv3_priv_protocol_combo.addItem("AES", "aes")
        snmpv3_layout.addRow(self.snmpv3_priv_protocol_label, self.snmpv3_priv_protocol_combo)
        
        # 加密密码
        self.snmpv3_priv_passphrase_label = QLabel("加密密码:", self.snmpv3_group)
        self.snmpv3_priv_passphrase_edit = QLineEdit(self.snmpv3_group)
        self.snmpv3_priv_passphrase_edit.setEchoMode(QLineEdit.Normal)  # 使用明文显示密码
        snmpv3_layout.addRow(self.snmpv3_priv_passphrase_label, self.snmpv3_priv_passphrase_edit)
        
        self.snmpv3_group.setLayout(snmpv3_layout)
        basic_layout.addRow("", self.snmpv3_group)
        
        # 更新间隔
        self.delay_spin = QSpinBox()
        self.delay_spin.setMinimum(1)
        self.delay_spin.setMaximum(86400)  # 1天
        self.delay_spin.setValue(60)  # 默认60秒
        self.delay_spin.setSuffix("s")  # 添加单位后缀
        basic_layout.addRow("更新间隔:", self.delay_spin)
        
        # 历史存储周期
        self.history_spin = QSpinBox()
        self.history_spin.setMinimum(1)
        self.history_spin.setMaximum(99999)
        self.history_spin.setValue(90)  # 默认90天
        basic_layout.addRow("历史存储周期(天):", self.history_spin)
        
        # 趋势存储周期
        self.trends_spin = QSpinBox()
        self.trends_spin.setMinimum(0)
        self.trends_spin.setMaximum(99999)
        self.trends_spin.setValue(365)  # 默认365天
        basic_layout.addRow("趋势存储周期(天):", self.trends_spin)
        
        # 将描述区域改为单行
        self.description_edit = QLineEdit()  # 使用QLineEdit代替QTextEdit
        self.description_edit.setPlaceholderText("输入描述信息...")
        basic_layout.addRow("描述:", self.description_edit)
        
        # 添加基本信息标签页
        tab_widget.addTab(basic_tab, "基本信息")
        
        # 批量创建标签页
        batch_tab = QWidget()
        batch_layout = QVBoxLayout(batch_tab)
        
        # 导入控件组
        import_group = QGroupBox("Excel导入")
        import_layout = QVBoxLayout(import_group)
        
        # 说明标签
        import_label = QLabel(
            "通过Excel文件批量导入监控项，您可以下载模板，填写后导入。\n"
            "注意：模板中包含示例数据，导入前请标记'是否示例'列为'否'或删除示例行。"
        )
        import_label.setWordWrap(True)
        import_layout.addWidget(import_label)
        
        # 按钮组
        buttons_layout = QHBoxLayout()
        
        # 下载模板按钮
        self.template_button = QPushButton("下载Excel模板")
        self.template_button.clicked.connect(self.download_excel_template)
        buttons_layout.addWidget(self.template_button)
        
        # 导入按钮
        self.import_button = QPushButton("从Excel导入")
        self.import_button.clicked.connect(self.import_from_excel)
        buttons_layout.addWidget(self.import_button)
        
        buttons_layout.addStretch()
        import_layout.addLayout(buttons_layout)
        
        batch_layout.addWidget(import_group)
        batch_layout.addStretch()
        
        # 添加批量创建标签页
        tab_widget.addTab(batch_tab, "批量创建")
        
        # 高级标签页
        advanced_tab = QWidget()
        advanced_layout = QFormLayout(advanced_tab)
        
        # 单位
        self.units_edit = QLineEdit()
        advanced_layout.addRow("单位:", self.units_edit)
        
        # 应用集
        self.applications_edit = QLineEdit()
        self.applications_edit.setPlaceholderText("应用集名称，多个用逗号分隔")
        advanced_layout.addRow("应用集:", self.applications_edit)
        
        # 预处理
        self.preprocessing_edit = QTextEdit()
        self.preprocessing_edit.setPlaceholderText("预处理步骤，JSON格式")
        advanced_layout.addRow("预处理:", self.preprocessing_edit)
        
        # 添加高级标签页
        tab_widget.addTab(advanced_tab, "高级设置")
        
        # 设置标签页比例更小，与触发器对话框保持一致
        main_layout.addWidget(tab_widget, 1)
        
        # 添加按钮
        button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
        button_box.accepted.connect(self.accept)
        button_box.rejected.connect(self.reject)
        main_layout.addWidget(button_box)
        
        # 设置对话框属性
        self.setLayout(main_layout)
        
        # 连接信号槽
        self.type_combo.currentIndexChanged.connect(self.on_type_changed)
        
        # 根据第一个主机的端口自动设置客户端类型
        if first_host_port:
            if first_host_port == "161":
                # 查找SNMP agent项在下拉列表中的索引
                snmp_agent_index = -1
                for i in range(self.type_combo.count()):
                    if self.type_combo.itemData(i) == 20:  # SNMP agent的type_id是20
                        snmp_agent_index = i
                        break
                
                if snmp_agent_index >= 0:
                    # 设置为SNMP agent
                    self.type_combo.setCurrentIndex(snmp_agent_index)
                    # 触发类型变更事件，以便更新UI
                    self.on_type_changed()
                    logger.info(f"基于端口自动设置客户端类型为SNMP 代理，端口号: {first_host_port}")
            elif first_host_port == "10050":
                # 查找Zabbix Agent项在下拉列表中的索引
                zabbix_agent_index = -1
                for i in range(self.type_combo.count()):
                    if self.type_combo.itemData(i) == 0:  # Zabbix Agent的type_id是0
                        zabbix_agent_index = i
                        break
                
                if zabbix_agent_index >= 0:
                    # 设置为Zabbix Agent
                    self.type_combo.setCurrentIndex(zabbix_agent_index)
                    # 触发类型变更事件，以便更新UI
                    self.on_type_changed()
                    logger.info(f"基于端口自动设置客户端类型为Zabbix Agent，端口号: {first_host_port}")
        
        # 自动选择表格中的第一行，触发选择事件
        if len(self.hosts) > 0:
            self.host_table.selectRow(0)
            logger.info("自动选择第一个主机")
            # 如果表格中第一个主机是SNMP设备（端口161），自动触发SNMP设置
            if port_161_found:
                logger.info("检测到SNMP设备，自动设置为SNMP 代理")
    
    def on_type_changed(self, index=None):
        """根据选择的类型显示不同的配置项"""
        item_type = self.type_combo.currentData()
        logger.info(f"监控项类型变更为: {item_type} (索引: {index if index is not None else '未提供'})")
        
        # 处理SNMP相关的配置
        is_snmp_type = item_type in [20, 17]  # SNMP agent, SNMP trap
        self.snmp_community_label.setVisible(is_snmp_type)
        self.community_edit.setVisible(is_snmp_type)
        self.snmp_oid_label.setVisible(is_snmp_type)
        self.oid_edit.setVisible(is_snmp_type)
        self.port_label.setVisible(is_snmp_type)
        self.port_edit.setVisible(is_snmp_type)
        
        # 默认先隐藏SNMPv3配置区域，后面会根据SNMP版本决定是否显示
        self.snmpv3_group.setVisible(False)
        
        # 如果选择了SNMP类型，尝试获取并填充主机的SNMPv3配置
        if is_snmp_type:
            # 获取当前选中的主机ID
            selected_items = self.host_table.selectedIndexes()
            selected_host_id = None  # 初始化变量
            
            if not selected_items:
                logger.info("没有选中的主机，无法获取SNMPv3配置")
                return
            
            selected_row = selected_items[0].row()
            selected_host_id = self.host_table.item(selected_row, 0).text()
            
            logger.info(f"正在获取主机 {selected_host_id} 的接口信息以检查SNMPv3配置")
            
            try:
                # 直接通过API获取完整的SNMPv3详情
                interface_data = self.get_host_interface_details(selected_host_id)
                
                if not interface_data:
                    logger.info(f"无法获取主机 {selected_host_id} 的详细接口信息")
                    # 回退到使用普通接口API
                    host_interfaces = self.api.get_host_interfaces(selected_host_id)
                else:
                    # 使用直接API调用获取的详细接口信息
                    host_interfaces = interface_data
                    logger.info(f"使用直接API调用获取的 {len(host_interfaces)} 个详细接口")
                
                if not host_interfaces:
                    logger.info(f"主机 {selected_host_id} 没有接口信息")
                    return
                
                logger.info(f"获取到接口数量: {len(host_interfaces)}")
                
                # 记录所有接口详情以便调试
                for i, interface in enumerate(host_interfaces):
                    try:
                        interface_json = json.dumps(interface, ensure_ascii=False, indent=2)
                        logger.info(f"接口 {i+1} JSON: {interface_json}")
                    except:
                        logger.info(f"接口 {i+1}: {interface}")
                
                # 遍历接口寻找SNMP配置
                for interface in host_interfaces:
                    # 检查接口类型是否为SNMP (type=2)
                    if interface.get("type") == "2":
                        logger.info(f"找到SNMP接口: {interface}")
                        
                        # 直接检查SNMPv3的相关字段
                        security_name = None
                        security_level = None
                        auth_protocol = None
                        auth_passphrase = None
                        priv_protocol = None
                        priv_passphrase = None
                        snmp_version = None  # 初始化snmp_version变量
                        
                        # 首先尝试使用直接添加到接口对象的snmpv3_*字段
                        if "snmpv3_version" in interface and interface["snmpv3_version"] == "3":
                            logger.info("从接口对象中直接找到SNMPv3参数")
                            snmp_version = "3"
                            security_name = interface.get("snmpv3_securityname")
                            security_level = interface.get("snmpv3_securitylevel")
                            auth_protocol = interface.get("snmpv3_authprotocol")
                            auth_passphrase = interface.get("snmpv3_authpassphrase")
                            priv_protocol = interface.get("snmpv3_privprotocol")
                            priv_passphrase = interface.get("snmpv3_privpassphrase")
                        # 然后尝试从details_parsed字段获取
                        elif "details_parsed" in interface:
                            details = interface["details_parsed"]
                            logger.info(f"从details_parsed字段获取SNMPv3参数: {details}")
                            
                            if isinstance(details, dict):
                                snmp_version = details.get("version")
                                if snmp_version == "3":
                                    security_name = details.get("securityname")
                                    security_level = details.get("securitylevel")
                                    auth_protocol = details.get("authprotocol")
                                    auth_passphrase = details.get("authpassphrase")
                                    priv_protocol = details.get("privprotocol")
                                    priv_passphrase = details.get("privpassphrase")
                        # 最后尝试从原始details字段获取
                        elif "details" in interface:
                            details = interface["details"]
                            # 处理details为字符串的情况
                            if isinstance(details, str) and details:
                                try:
                                    details = json.loads(details)
                                    logger.info(f"解析SNMP详情JSON字符串: {details}")
                                    
                                    if isinstance(details, dict):
                                        snmp_version = details.get("version")
                                        if snmp_version == "3":
                                            security_name = details.get("securityname")
                                            security_level = details.get("securitylevel")
                                            auth_protocol = details.get("authprotocol")
                                            auth_passphrase = details.get("authpassphrase")
                                            priv_protocol = details.get("privprotocol")
                                            priv_passphrase = details.get("privpassphrase")
                                except (json.JSONDecodeError, ValueError):
                                    logger.error(f"无法解析SNMP详情字符串: {details}")
                            elif isinstance(details, dict):
                                snmp_version = details.get("version")
                                if snmp_version == "3":
                                    security_name = details.get("securityname")
                                    security_level = details.get("securitylevel")
                                    auth_protocol = details.get("authprotocol")
                                    auth_passphrase = details.get("authpassphrase")
                                    priv_protocol = details.get("privprotocol")
                                    priv_passphrase = details.get("privpassphrase")
                        
                        # 记录提取的SNMPv3参数
                        logger.info(f"提取的SNMPv3参数:")
                        logger.info(f" - 安全名称: {security_name}")
                        logger.info(f" - 安全级别: {security_level}")
                        logger.info(f" - 认证协议: {auth_protocol}")
                        logger.info(f" - 认证密码: {auth_passphrase}")
                        logger.info(f" - 加密协议: {priv_protocol}")
                        logger.info(f" - 加密密码: {priv_passphrase}")
                        logger.info(f" - SNMP版本: {snmp_version}")
                        
                        # 设置SNMP社区
                        community = interface.get("community", "public")
                        if "details_parsed" in interface and isinstance(interface["details_parsed"], dict):
                            community = interface["details_parsed"].get("community", community)
                        self.community_edit.setText(community)
                        
                        # 设置SNMP端口
                        port = interface.get("port", "161")
                        self.port_edit.setText(port)
                        
                        # 根据SNMP版本决定是否显示SNMPv3配置区域
                        is_snmpv3 = False
                        if snmp_version == "3":
                            is_snmpv3 = True
                            logger.info("检测到SNMPv3配置")
                            # 只有在SNMP版本为3时才显示SNMPv3配置区域
                            self.snmpv3_group.setVisible(True)
                            # SNMPv3不使用社区字段，隐藏它
                            self.snmp_community_label.setVisible(False)
                            self.community_edit.setVisible(False)
                            
                            # 如果是SNMPv3，填充SNMPv3配置
                            logger.info("开始填充SNMPv3配置")
                            
                            # 设置安全名称
                            if security_name:
                                self.snmpv3_security_name_edit.setText(security_name)
                                logger.info(f"设置安全名称: {security_name}")
                            
                            # 设置安全级别
                            if security_level:
                                try:
                                    security_level_int = int(security_level)
                                    index = self.snmpv3_security_level_combo.findData(security_level_int)
                                    if index >= 0:
                                        self.snmpv3_security_level_combo.setCurrentIndex(index)
                                        logger.info(f"设置安全级别: {security_level_int}, 索引: {index}")
                                except (ValueError, TypeError):
                                    logger.warning(f"无法将安全级别转换为整数: {security_level}")
                            
                            # 设置认证协议
                            if auth_protocol:
                                auth_protocol_str = auth_protocol
                                if auth_protocol == "0":
                                    auth_protocol_str = "md5"
                                    logger.info(f"将认证协议0转换为md5")
                                elif auth_protocol == "1":
                                    auth_protocol_str = "sha"
                                    logger.info(f"将认证协议1转换为sha")
                                
                                # 查找对应的索引
                                index = -1
                                for i in range(self.snmpv3_auth_protocol_combo.count()):
                                    if self.snmpv3_auth_protocol_combo.itemData(i) == auth_protocol_str:
                                        index = i
                                        break
                                
                                if index >= 0:
                                    self.snmpv3_auth_protocol_combo.setCurrentIndex(index)
                                    logger.info(f"设置认证协议: {auth_protocol_str}, 索引: {index}")
                                else:
                                    # 模糊匹配
                                    if auth_protocol == "0" or (isinstance(auth_protocol, str) and "md5" in auth_protocol.lower()):
                                        self.snmpv3_auth_protocol_combo.setCurrentIndex(0)
                                        logger.info("模糊匹配设置认证协议为MD5")
                                    elif auth_protocol == "1" or (isinstance(auth_protocol, str) and "sha" in auth_protocol.lower()):
                                        self.snmpv3_auth_protocol_combo.setCurrentIndex(1)
                                        logger.info("模糊匹配设置认证协议为SHA")
                            
                            # 设置认证密码
                            if auth_passphrase:
                                self.snmpv3_auth_passphrase_edit.setText(auth_passphrase)
                                logger.info(f"设置SNMPv3认证密码: {auth_passphrase}")
                            
                            # 设置加密协议
                            if priv_protocol:
                                priv_protocol_str = priv_protocol
                                if priv_protocol == "0":
                                    priv_protocol_str = "des"
                                    logger.info(f"将加密协议0转换为des")
                                elif priv_protocol == "1":
                                    priv_protocol_str = "aes"
                                    logger.info(f"将加密协议1转换为aes")
                                
                                # 查找对应的索引
                                index = -1
                                for i in range(self.snmpv3_priv_protocol_combo.count()):
                                    if self.snmpv3_priv_protocol_combo.itemData(i) == priv_protocol_str:
                                        index = i
                                        break
                                
                                if index >= 0:
                                    self.snmpv3_priv_protocol_combo.setCurrentIndex(index)
                                    logger.info(f"设置加密协议: {priv_protocol_str}, 索引: {index}")
                                else:
                                    # 模糊匹配
                                    if priv_protocol == "0" or (isinstance(priv_protocol, str) and "des" in priv_protocol.lower()):
                                        self.snmpv3_priv_protocol_combo.setCurrentIndex(0)
                                        logger.info("模糊匹配设置加密协议为DES")
                                    elif priv_protocol == "1" or (isinstance(priv_protocol, str) and "aes" in priv_protocol.lower()):
                                        self.snmpv3_priv_protocol_combo.setCurrentIndex(1)
                                        logger.info("模糊匹配设置加密协议为AES")
                            
                            # 设置加密密码
                            if priv_passphrase:
                                self.snmpv3_priv_passphrase_edit.setText(priv_passphrase)
                                logger.info(f"设置SNMPv3加密密码: {priv_passphrase}")
                            
                            logger.info("SNMPv3配置填充完成")
                        else:
                            # SNMP版本不是3，确保SNMPv3配置区域隐藏
                            logger.info(f"当前SNMP版本为{snmp_version}，隐藏SNMPv3配置区域")
                            self.snmpv3_group.setVisible(False)
                            # 非SNMPv3需要显示社区字段
                            self.snmp_community_label.setVisible(True)
                            self.community_edit.setVisible(True)
                            break
            except Exception as e:
                logger.error(f"获取SNMPv3配置时出错: {str(e)}")
                import traceback
                logger.error(f"错误详情: {traceback.format_exc()}")
    
    def get_host_interface_details(self, hostid):
        """直接通过API获取完整的主机接口信息，包括SNMPv3详情"""
        try:
            if hasattr(self.api, 'auth') and hasattr(self.api, 'url'):
                import requests
                # 使用hostinterface.get API直接获取完整详情
                json_request = {
                    "jsonrpc": "2.0",
                    "method": "hostinterface.get",
                    "params": {
                        "output": "extend",
                        "hostids": hostid,
                        "selectHosts": ["host"],
                        "details": True  # 请求详细信息
                    },
                    "auth": self.api.auth,
                    "id": 1
                }
                
                url = self.api.url
                headers = {'Content-Type': 'application/json-rpc'}
                
                logger.info(f"直接调用Zabbix API获取接口详情: {json.dumps(json_request)}")
                try:
                    r = requests.post(url, json=json_request, headers=headers)
                    response = r.json()
                    
                    logger.info(f"API返回结果: {response}")
                    
                    if "result" in response and response["result"]:
                        # 处理返回结果
                        interfaces = response["result"]
                        logger.info(f"成功获取 {len(interfaces)} 个接口详情")
                        
                        # 添加预处理，解析details字段
                        for interface in interfaces:
                            if "details" in interface:
                                try:
                                    if isinstance(interface["details"], str):
                                        details_dict = json.loads(interface["details"])
                                        interface["details_parsed"] = details_dict
                                        logger.info(f"成功解析接口详情: {details_dict}")
                                except Exception as parse_err:
                                    logger.error(f"解析接口详情失败: {str(parse_err)}")
                                    interface["details_parsed"] = {}
                        
                        return interfaces
                    else:
                        if "error" in response:
                            logger.error(f"获取接口详情API错误: {response['error']}")
                        else:
                            logger.error("API返回空结果")
                            
                        return []
                except Exception as api_err:
                    logger.error(f"API请求失败: {str(api_err)}")
                    return []
            else:
                logger.warning("API客户端不包含auth或url属性，无法直接调用")
                return []
        except Exception as e:
            logger.error(f"直接调用API获取接口详情时出错: {str(e)}")
            import traceback
            logger.error(f"错误详情: {traceback.format_exc()}")
            return []
    
    def on_key_changed(self):
        """当键值改变时的处理函数"""
        key = self.key_edit.text().strip()
        
        # 如果键值为空，不处理
        if not key:
            return
            
        # 检查是否是SNMP格式键值
        if key.startswith("snmp.get[") or key.startswith("snmpget["):
            # 尝试提取OID
            try:
                # 提取括号中的内容
                oid_start = key.find("[") + 1
                oid_end = key.rfind("]")
                if oid_start > 0 and oid_end > oid_start:
                    oid = key[oid_start:oid_end]
                    
                    # 如果有逗号分隔的参数，仅取第一部分
                    if "," in oid:
                        oid = oid.split(",")[0]
                    
                    # 如果OID不同，更新OID输入框
                    if oid != self.oid_edit.text():
                        self.oid_edit.setText(oid)
                    
                    # 如果当前不是SNMP类型，切换到SNMP agent类型
                    type_id = self.type_combo.currentData()
                    if type_id not in [20, 17]:
                        # 查找SNMP agent项在下拉列表中的索引
                        snmp_agent_index = -1
                        for i in range(self.type_combo.count()):
                            if self.type_combo.itemData(i) == 20:  # SNMP agent的type_id是20
                                snmp_agent_index = i
                                break
                        
                        if snmp_agent_index >= 0:
                            # 切换到SNMP agent类型
                            self.type_combo.setCurrentIndex(snmp_agent_index)
            except Exception as e:
                logger.warning(f"从键值提取OID时出错: {e}")
    
    def on_host_selection_changed(self):
        """当选择的主机变更时的处理函数"""
        selected_items = self.host_table.selectedIndexes()
        if not selected_items:
            return
            
        selected_row = selected_items[0].row()
        selected_host_id = self.host_table.item(selected_row, 0).text()
        selected_port = self.host_table.item(selected_row, 4).text()
        
        # 检查是否有明确的端口记录
        if selected_port:
            # 根据端口号设置客户端类型
            if selected_port == "10050":
                logger.info(f"主机 {selected_host_id} 使用端口 10050，设置为Zabbix Agent")
                # 查找Zabbix Agent项在下拉列表中的索引
                zabbix_agent_index = -1
                for i in range(self.type_combo.count()):
                    if self.type_combo.itemData(i) == 0:  # Zabbix Agent的type_id是0
                        zabbix_agent_index = i
                        break
                
                if zabbix_agent_index >= 0:
                    # 设置为Zabbix Agent
                    self.type_combo.setCurrentIndex(zabbix_agent_index)
                    # 触发类型变更事件，以便更新UI
                    self.on_type_changed()
                    return  # 端口已确定，无需进一步检查
            elif selected_port == "161":
                logger.info(f"主机 {selected_host_id} 使用端口 161，设置为SNMP 代理")
                # 查找SNMP agent项在下拉列表中的索引
                snmp_agent_index = -1
                for i in range(self.type_combo.count()):
                    if self.type_combo.itemData(i) == 20:  # SNMP agent的type_id是20
                        snmp_agent_index = i
                        break
                
                if snmp_agent_index >= 0:
                    # 设置为SNMP agent
                    self.type_combo.setCurrentIndex(snmp_agent_index)
                    # 触发类型变更事件，以便更新UI
                    self.on_type_changed()
                    return  # 端口已确定，无需进一步检查
                    
        # 如果没有明确的端口信息，检查主机是否有SNMP接口
        try:
            # 获取主机的接口
            host_interfaces = self.api.get_host_interfaces(selected_host_id)
            
            # 首先查找SNMP接口（类型为2）
            has_snmp_interface = False
            for interface in host_interfaces:
                if interface.get('type') == '2':  # SNMP接口
                    has_snmp_interface = True
                    # 顺便记录端口信息
                    port = interface.get('port')
                    if port:
                        logger.info(f"发现SNMP接口，端口号: {port}")
                        # 更新表格中的端口显示
                        self.host_table.item(selected_row, 4).setText(port)
                        if port == "161":
                            self.host_table.item(selected_row, 4).setBackground(QColor(230, 230, 255))  # 淡蓝色
                    break
            
            # 如果没有SNMP接口，检查是否有Zabbix Agent接口（类型为1）
            if not has_snmp_interface:
                for interface in host_interfaces:
                    if interface.get('type') == '1':  # Zabbix Agent接口
                        # 记录端口信息
                        port = interface.get('port')
                        if port:
                            logger.info(f"发现Zabbix Agent接口，端口号: {port}")
                            # 更新表格中的端口显示
                            self.host_table.item(selected_row, 4).setText(port)
                            if port == "10050":
                                self.host_table.item(selected_row, 4).setBackground(QColor(230, 255, 230))  # 淡绿色
                        break
                    
            # 如果有SNMP接口，自动设置客户端类型为SNMP 代理
            if has_snmp_interface:
                logger.info(f"检测到主机 {selected_host_id} 有SNMP接口，自动设置为SNMP 代理")
                # 查找SNMP agent项在下拉列表中的索引
                snmp_agent_index = -1
                for i in range(self.type_combo.count()):
                    if self.type_combo.itemData(i) == 20:  # SNMP agent的type_id是20
                        snmp_agent_index = i
                        break
                
                if snmp_agent_index >= 0:
                    # 设置为SNMP agent
                    self.type_combo.setCurrentIndex(snmp_agent_index)
                    # 触发类型变更事件，以便更新UI
                    self.on_type_changed()
            else:
                logger.info(f"主机 {selected_host_id} 没有SNMP接口，使用默认设置")
        except Exception as e:
            logger.error(f"检查主机接口时出错: {str(e)}")
    
    def show_oid_help(self):
        """显示OID帮助信息"""
        help_text = """
<h3>SNMP OID 格式说明</h3>
<p>OID(对象标识符)是一个用于唯一标识SNMP管理对象的数字序列。</p>

<h4>格式要求:</h4>
<ul>
<li>以点(.)开头</li>
<li>由数字和点组成</li>
<li>最常见的OID以.1.3.6.1开头</li>
<li>例如: .1.3.6.1.2.1.1.1.0 表示系统描述</li>
</ul>

<h4>获取OID的方法:</h4>
<ol>
<li>使用snmpwalk工具: <pre>snmpwalk -v 2c -c public &lt;主机IP&gt; .</pre></li>
<li>使用snmpget工具查询特定OID: <pre>snmpget -v 2c -c public &lt;主机IP&gt; .1.3.6.1.2.1.1.1.0</pre></li>
<li>使用MIB浏览器工具</li>
</ol>
        """
        
        QMessageBox.information(self, "SNMP OID 帮助", help_text)
    
    def download_excel_template(self):
        """下载Excel模板"""
        if not PANDAS_AVAILABLE:
            QMessageBox.warning(self, "功能不可用", "未安装pandas库，无法使用Excel功能")
            return
            
        # 打开保存文件对话框
        file_path, _ = QFileDialog.getSaveFileName(
            self, "保存Excel模板", "监控项综合模板.xlsx", "Excel文件 (*.xlsx)"
        )
        
        if not file_path:
            return  # 用户取消了保存
            
        try:
            # 创建多种类型示例的数据结构
            data = {
                "监控项名称": [
                    "# Zabbix Agent示例 (以下4项)",
                    "系统启动时间", 
                    "CPU使用率", 
                    "可用内存",
                    "磁盘空间使用率",
                    "# SNMP Agent示例 (以下4项) - OID必须填写",
                    "网络接口1入站流量", 
                    "网络接口1出站流量",
                    "系统描述",
                    "CPU负载"
                ],
                "键值": [
                    "",
                    "system.uptime", 
                    "system.cpu.util[,user]", 
                    "vm.memory.size[available]",
                    "vfs.fs.size[/,pused]",
                    "",
                    "snmp.get[.1.3.6.1.2.1.2.2.1.10.1]", 
                    "snmp.get[.1.3.6.1.2.1.2.2.1.16.1]",
                    "snmp.get[.1.3.6.1.2.1.1.1.0]",
                    "snmp.get[.1.3.6.1.2.1.25.3.3.1.2.1]"
                ],
                "类型": [
                    "",
                    "Zabbix 采集器", 
                    "Zabbix 采集器", 
                    "Zabbix 采集器",
                    "Zabbix 采集器",
                    "",
                    "SNMP 采集器", 
                    "SNMP 采集器",
                    "SNMP 采集器",
                    "SNMP 采集器"
                ],
                "OID": [
                    "",
                    "", 
                    "", 
                    "",
                    "",
                    "",
                    ".1.3.6.1.2.1.2.2.1.10.1", 
                    ".1.3.6.1.2.1.2.2.1.16.1",
                    ".1.3.6.1.2.1.1.1.0",
                    ".1.3.6.1.2.1.25.3.3.1.2.1"
                ],
                "数据类型": [
                    "",
                    "数值(无符号整数)", 
                    "数值(浮点)", 
                    "数值(浮点)",
                    "数值(浮点)",
                    "",
                    "数值(无符号整数)", 
                    "数值(无符号整数)",
                    "字符",
                    "数值(无符号整数)"
                ],
                "更新间隔": [
                    "",
                    "60s", 
                    "30s", 
                    "60s",
                    "300s",
                    "",
                    "60s", 
                    "60s",
                    "3600s",
                    "60s"
                ],
                "单位": [
                    "",
                    "uptime", 
                    "%", 
                    "B",
                    "%",
                    "",
                    "bps", 
                    "bps",
                    "",
                    "%"
                ],
                "描述": [
                    "",
                    "系统启动时间", 
                    "CPU用户空间使用率", 
                    "可用内存大小",
                    "根分区使用率",
                    "",
                    "网络接口1入站流量", 
                    "网络接口1出站流量",
                    "系统描述信息",
                    "CPU负载百分比"
                ],
                "是否示例": [
                    "是",
                    "是", 
                    "是", 
                    "是",
                    "是",
                    "是",
                    "是", 
                    "是",
                    "是",
                    "是"
                ]
            }
            
            # 创建DataFrame并保存为Excel
            df = pd.DataFrame(data)
            
            # 尝试创建Excel写入器(带使用说明)
            try:
                with pd.ExcelWriter(file_path, engine='openpyxl') as writer:
                    df.to_excel(writer, sheet_name='监控项模板', index=False)
                    
                    # 添加使用说明sheet
                    instructions = pd.DataFrame({
                        "使用说明": [
                            "1. 此模板包含Zabbix Agent和SNMP Agent两种类型的监控项示例",
                            "2. 复制需要的示例行并修改为您需要的配置",
                            "3. 删除所有标记为'是'的示例行和注释行(以#开头)",
                            "4. Zabbix Agent监控项不需要填写OID",
                            "5. SNMP监控项必须填写OID字段",
                            "6. SNMP社区、端口和SNMPv3配置将自动从主机获取",
                            "7. 数据类型常用值: 数值(无符号整数)=3, 数值(浮点)=0, 字符=1, 日志=2, 文本=4",
                            "8. 更新间隔格式为数字+单位，如: 30s, 1m, 1h, 1d",
                            "9. 导入前请确保主机具有对应类型的接口(Agent或SNMP)"
                        ]
                    })
                    instructions.to_excel(writer, sheet_name='使用说明', index=False)
            except Exception as sheet_err:
                # 如果无法创建多sheet，则只保存主sheet
                logger.warning(f"无法创建多sheet Excel: {sheet_err}，将只保存主数据表")
            df.to_excel(file_path, index=False)
            
            QMessageBox.information(
                self, 
                "下载成功", 
                f"Excel模板已保存到: {file_path}\n包含Zabbix Agent和SNMP Agent示例，SNMP配置将自动从主机获取"
            )
            
        except Exception as e:
            logger.error(f"生成Excel模板失败: {e}")
            QMessageBox.critical(self, "下载失败", f"生成Excel模板失败: {e}")
    
    def import_from_excel(self):
        """从Excel导入监控项"""
        if not PANDAS_AVAILABLE:
            QMessageBox.warning(self, "功能不可用", "未安装pandas库，无法使用Excel功能")
            return
        
        # 打开文件对话框
        file_path, _ = QFileDialog.getOpenFileName(
            self, "选择Excel文件", "", "Excel文件 (*.xlsx *.xls)"
        )
        
        if not file_path:
            return  # 用户取消了选择
        
        try:
            # 读取Excel文件
            df = pd.read_excel(file_path)
            
            # 检查必要的列是否存在
            required_columns = ["监控项名称", "键值", "类型"]
            missing_columns = [col for col in required_columns if col not in df.columns]
            if missing_columns:
                QMessageBox.critical(
                    self, "格式错误", f"Excel文件缺少必要的列: {', '.join(missing_columns)}"
                )
                return
            
            # 检查是否有示例标记列，如果有，过滤掉示例行
            if "是否示例" in df.columns:
                df = df[df["是否示例"] != "是"]
            
            # 过滤掉注释行（以#开头的行）
            df = df[~df["监控项名称"].astype(str).str.startswith("#")]
            
            # 如果没有数据行，提示用户
            if df.empty:
                QMessageBox.warning(
                    self, "没有数据", "Excel文件中没有有效的数据行或所有行都是示例/注释"
                )
                return
            
            # 获取选中的主机
            selected_hosts = self.get_selected_hosts()
            if not selected_hosts:
                QMessageBox.warning(self, "未选择主机", "请先在主机界面选择要导入监控项的主机")
                return
            
            # 确认对话框
            msg = f"将为{len(selected_hosts)}个主机批量导入{len(df)}个监控项，总共{len(selected_hosts) * len(df)}个操作。确定继续？"
            reply = QMessageBox.question(
                self, "确认导入", msg, QMessageBox.Yes | QMessageBox.No, QMessageBox.No
            )
            
            if reply == QMessageBox.No:
                return
            
            # 处理每个主机
            success_count = 0
            error_count = 0
            
            # 计算总操作数
            total_operations = len(selected_hosts) * len(df)
            
            # 创建进度对话框
            progress = QProgressDialog(self)
            progress.setWindowTitle("批量创建监控项")
            progress.setLabelText("正在导入监控项...")
            progress.setRange(0, total_operations)
            progress.setMinimumDuration(0)  # 立即显示进度条
            progress.setModal(True)  # 使用setModal替代setWindowModality
            progress.setAutoClose(True)
            progress.setAutoReset(True)
            
            progress_count = 0
            
            for host_index, host in enumerate(selected_hosts):
                host_id = host["hostid"]
                host_name = host["host"]
                    
                # 处理每一行
                for row_index, row in enumerate(df.itertuples(), 1):
                    if progress.wasCanceled():
                        break
                        
                    # 更新进度条文本
                    current_item = row_index
                    total_items = len(df)
                    progress.setLabelText(f"正在为主机 {host_name} ({host_index + 1}/{len(selected_hosts)}) 创建第 {current_item}/{total_items} 个监控项...")
                    progress.setValue(progress_count)
                    progress_count += 1
                    
                    try:
                        # 准备监控项参数
                        item_params = {
                            "name": str(row.监控项名称),
                            "key_": str(row.键值).strip(),  # 保持Excel中的键值不变
                            "hostid": host_id,
                        }
                        
                        # 处理监控项类型
                        item_type = 0  # 默认为Zabbix Agent
                        if "类型" in df.columns and not pd.isna(row.类型):
                            type_text = str(row.类型)
                            type_map = {
                                "Zabbix 采集器": 0,
                                "Zabbix 主动采集器": 1,
                                "简单检查": 2,
                                "SNMP 采集器": 20,
                                "SNMP 陷阱": 17,
                                "HTTP 采集器": 19,
                                "JMX 采集器": 16,
                                "IPMI 采集器": 12,
                            }
                            if type_text in type_map:
                                item_type = type_map[type_text]
                            elif type_text.isdigit():
                                item_type = int(type_text)
                        item_params["type"] = item_type
                        
                        # 如果是SNMP类型，设置OID
                        if item_type in [20, 17]:  # SNMP agent, SNMP trap
                            if "OID" in df.columns and not pd.isna(row.OID):
                                item_params["snmp_oid"] = str(row.OID).strip()
                        
                        # 处理数据类型
                        value_type = 0  # 默认为数值(浮点)
                        if "数据类型" in df.columns and not pd.isna(row.数据类型):
                            vtype_text = str(row.数据类型)
                            vtype_map = {
                                "数值(浮点)": 0,
                                "字符": 1,
                                "日志": 2,
                                "数值(无符号整数)": 3,
                                "文本": 4
                            }
                            if vtype_text in vtype_map:
                                value_type = vtype_map[vtype_text]
                            elif vtype_text.isdigit():
                                value_type = int(vtype_text)
                        item_params["value_type"] = value_type
                        
                        # 处理更新间隔
                        if "更新间隔" in df.columns and not pd.isna(row.更新间隔):
                            item_params["delay"] = str(row.更新间隔)
                        else:
                            item_params["delay"] = "60s"  # 默认60秒
                        
                        # 处理描述
                        if "描述" in df.columns and not pd.isna(row.描述):
                            item_params["description"] = str(row.描述)
                        else:
                            item_params["description"] = ""
                        
                        # 处理单位
                        if "单位" in df.columns and not pd.isna(row.单位):
                            item_params["units"] = str(row.单位)
                        else:
                            item_params["units"] = ""
                        
                        # 预处理监控项参数（包括接口ID等）
                        processed_params = self.preprocess_item_params(item_params, host_id, host_name)
                        
                        # 创建监控项
                        try:
                            result = self.api._call("item.create", processed_params)
                            if result and "itemids" in result:
                                success_count += 1
                                logger.info(f"为主机 {host_name} 成功创建监控项 {item_params['name']}")
                            else:
                                error_count += 1
                                logger.error(f"为主机 {host_name} 创建监控项 {item_params['name']} 失败: 未返回itemids")
                        except Exception as api_err:
                            error_count += 1
                            logger.error(f"为主机 {host_name} 创建项 {item_params['name']} 时发生错误: {api_err}")
                        
                    except Exception as row_err:
                        error_count += 1
                        logger.error(f"处理Excel第{row_index}行时出错: {row_err}")
                
                    if progress.wasCanceled():
                        break
                
            progress.setValue(total_operations)
                
                # 显示结果
            if error_count == 0:
                QMessageBox.information(
                    self, "导入完成", f"成功导入{success_count}个监控项。"
                )
            else:
                QMessageBox.warning(
                    self, "导入完成", f"成功导入{success_count}个监控项，失败{error_count}个。请查看日志了解详情。"
                )
        
        except Exception as e:
            logger.error(f"导入Excel失败: {e}")
            import traceback
            logger.error(traceback.format_exc())
            QMessageBox.critical(self, "导入失败", f"导入Excel失败: {e}")

    def load_complete_host_info(self):
        """预先加载所有主机的完整信息"""
        try:
            # 获取所有主机ID
            hostids = [host.get('hostid') for host in self.hosts if host.get('hostid')]
            
            if not hostids:
                logger.warning("警告：没有找到任何主机ID")
                return
                
            logger.info(f"正在预先获取 {len(hostids)} 台主机的完整信息...")
            
            try:
                # 直接使用JSON-RPC调用获取完整主机信息
                if hasattr(self.api, 'auth') and hasattr(self.api, 'url'):
                    import requests
                    json_request = {
                        "jsonrpc": "2.0",
                        "method": "host.get",
                        "params": {
                            "hostids": hostids,
                            "output": ["hostid", "host", "name"]
                        },
                        "auth": self.api.auth,
                        "id": 0
                    }
                    
                    url = self.api.url
                    headers = {'Content-Type': 'application/json-rpc'}
                    r = requests.post(url, json=json_request, headers=headers)
                    response = r.json()
                    
                    if "result" in response and response["result"]:
                        host_data = response["result"]
                        logger.info(f"成功获取 {len(host_data)} 台主机的完整信息")
                        
                        # 建立映射关系
                        for host in host_data:
                            hostid = host.get("hostid")
                            technical_name = host.get("host")
                            visible_name = host.get("name")
                            
                            if hostid:
                                self.host_info_map[hostid] = host
                            
                            if visible_name and technical_name:
                                self.name_to_host_map[visible_name] = technical_name
                                logger.info(f"映射: 可见名称 '{visible_name}' -> 技术名称 '{technical_name}'")
                        
                        # 打印主机信息以便调试
                        for host in self.hosts:
                            hostid = host.get("hostid")
                            visible_name = host.get("name", "")
                            original_tech_name = host.get("host", "")
                            
                            if hostid in self.host_info_map:
                                technical_name = self.host_info_map[hostid].get("host", "")
                                logger.info(f"主机信息: ID={hostid}, 原始技术名称={original_tech_name}, 查询到的技术名称={technical_name}, 可见名称={visible_name}")
                                
                                # 更新原始host对象的host字段，确保后续处理使用正确的技术名称
                                if not original_tech_name and technical_name:
                                    host["host"] = technical_name
                                    logger.info(f"已更新主机 {visible_name} 的技术名称为 {technical_name}")
                            else:
                                logger.warning(f"警告: 无法找到主机 ID={hostid}, 可见名称={visible_name} 的完整信息")
                # 如果上面的方法失败，尝试使用API的do_request方法
                elif hasattr(self.api, '_call'):
                    response = self.api._call('host.get', {
                        'hostids': hostids,
                        'output': ["hostid", "host", "name"]
                    })
                    
                    if isinstance(response, dict) and "result" in response and response["result"]:
                        host_data = response["result"]
                        logger.info(f"成功获取 {len(host_data)} 台主机的完整信息")
                        
                        # 建立映射关系
                        for host in host_data:
                            hostid = host.get("hostid")
                            technical_name = host.get("host")
                            visible_name = host.get("name")
                            
                            if hostid:
                                self.host_info_map[hostid] = host
                            
                            if visible_name and technical_name:
                                self.name_to_host_map[visible_name] = technical_name
                        
                        # 更新原始host对象
                        for host in self.hosts:
                            hostid = host.get("hostid")
                            if hostid in self.host_info_map:
                                tech_name = self.host_info_map[hostid].get("host", "")
                                if not host.get("host") and tech_name:
                                    host["host"] = tech_name
            except Exception as api_err:
                logger.error(f"通过API获取主机完整信息失败: {str(api_err)}")
        except Exception as e:
            logger.error(f"加载主机完整信息时出错: {str(e)}") 
    
    def accept(self):
        """确认按钮处理函数"""
        try:
            # 检查必填字段
            if not self.name_edit.text():
                QMessageBox.warning(self, "验证失败", "监控项名称不能为空")
                return
            
            if not self.key_edit.text():
                QMessageBox.warning(self, "验证失败", "监控项键值不能为空")
                return
            
            # 检查SNMP配置
            item_type = self.type_combo.currentData()
            if item_type in [20, 17]:  # SNMP agent, SNMP trap
                if not self.oid_edit.text():
                    QMessageBox.warning(self, "验证失败", "使用SNMP类型时，OID不能为空")
                    return
            
            # 构建监控项参数
            items = []
            created_count = 0
            error_count = 0
            
            for host in self.hosts:
                host_id = host.get("hostid")
                if not host_id:
                    continue
                
                # 获取主机的接口ID
                host_interfaces = self.api.get_host_interfaces(host_id)
                interface_id = None
                
                # 查找合适的接口
                if host_interfaces and len(host_interfaces) > 0:
                    # 获取当前选择的监控项类型
                    item_type = self.type_combo.currentData()
                    
                    # 根据监控项类型选择合适的接口类型
                    # 0, 7 - Zabbix Agent 类型需要类型为1的接口
                    # 20, 17 - SNMP 类型需要类型为2的接口
                    # 12 - IPMI 类型需要类型为3的接口
                    # 16 - JMX 类型需要类型为4的接口
                    
                    required_interface_type = None
                    if item_type in [0, 7]:  # Zabbix Agent
                        required_interface_type = '1'
                    elif item_type in [20, 17]:  # SNMP
                        required_interface_type = '2'
                    elif item_type == 12:  # IPMI
                        required_interface_type = '3'
                    elif item_type == 16:  # JMX
                        required_interface_type = '4'
                    
                    # 首先查找对应类型的主接口
                    if required_interface_type:
                        for interface in host_interfaces:
                            if interface.get('type') == required_interface_type and interface.get('main') == '1':
                                interface_id = interface.get('interfaceid')
                                break
                        
                        # 如果找不到对应类型的主接口，查找任何对应类型的接口
                        if not interface_id:
                            for interface in host_interfaces:
                                if interface.get('type') == required_interface_type:
                                    interface_id = interface.get('interfaceid')
                                    break
                    
                    # 如果找不到对应类型的接口或无需特定类型接口，使用主接口
                    if not interface_id:
                        for interface in host_interfaces:
                            if interface.get('main') == '1':
                                interface_id = interface.get('interfaceid')
                                break
                    
                    # 如果还找不到，使用第一个接口
                    if not interface_id and host_interfaces:
                        interface_id = host_interfaces[0].get('interfaceid')
                
                # 如果没有找到接口ID，跳过该主机
                if not interface_id:
                    logger.warning(f"主机 {host.get('name')} (ID: {host_id}) 没有可用接口，跳过创建监控项")
                    continue
                
                # 确保item_type不为None
                if item_type is None:
                    item_type = 0  # 默认为Zabbix Agent (使用整数0)
                    logger.warning("监控项类型为None，使用默认值0(Zabbix Agent)")
                
                # 创建监控项配置
                item = {
                    "hostid": host_id,
                    "name": self.name_edit.text(),
                    "key_": self.key_edit.text(),
                    "type": item_type,  # 使用整数类型
                    "value_type": self.value_type_combo.currentData(),
                    "delay": str(self.delay_spin.value()) + "s",  # 添加单位后缀"s"
                    "history": str(self.history_spin.value()) + "d",  # 默认90天
                    "trends": str(self.trends_spin.value()) + "d",  # 默认365天
                    "interfaceid": interface_id,
                    "description": self.description_edit.text(),
                    "units": self.units_edit.text()
                }
                
                # 记录每个监控项的配置参数
                logger.debug(f"监控项配置: {item}")
                
                # 添加SNMP特有参数
                if item_type in [20, 17]:  # SNMP agent, SNMP trap
                    # 添加SNMP OID
                    oid = self.oid_edit.text()
                    item["snmp_oid"] = oid
                    logger.info(f"设置SNMP OID: {oid}")
                    
                    # 添加SNMP接口ID
                    # 获取当前选中的主机ID
                    selected_items = self.host_table.selectedIndexes()
                    if selected_items:
                        selected_row = selected_items[0].row()
                        selected_host_id = self.host_table.item(selected_row, 0).text()
                        
                        # 获取主机的SNMP接口
                        interfaces = self.api.get_host_interfaces(selected_host_id)
                        snmp_interface = None
                        for interface in interfaces:
                            if interface.get("type") == "2":  # SNMP接口类型为2
                                snmp_interface = interface
                                break
                        
                        if snmp_interface:
                            interface_id = snmp_interface.get("interfaceid")
                            if interface_id:
                                item["interfaceid"] = interface_id
                                logger.info(f"设置接口ID: {interface_id}")
                            else:
                                logger.warning("找到SNMP接口但没有接口ID")
                        else:
                            logger.warning(f"主机 {selected_host_id} 没有SNMP接口")
                    
                    # 添加SNMP端口 (如果已设置)
                    if hasattr(self, 'port_edit') and self.port_edit.text():
                        port = self.port_edit.text()
                        item["port"] = port
                        logger.info(f"设置SNMP端口: {port}")
                    
                    # 如果SNMPv3配置区域可见，则添加SNMPv3相关参数
                    if self.snmpv3_group.isVisible():
                        logger.info("添加SNMPv3配置参数")
                        
                        # 添加安全名称
                        security_name = self.snmpv3_security_name_edit.text()
                        if security_name:
                            item["snmpv3_securityname"] = security_name
                            logger.info(f"设置SNMPv3安全名称: {security_name}")
                        
                        # 添加安全级别
                        security_level = self.snmpv3_security_level_combo.currentData()
                        if security_level is not None:
                            # 确保安全级别是整数
                            if isinstance(security_level, str):
                                try:
                                    security_level = int(security_level)
                                except (ValueError, TypeError):
                                    logger.warning(f"无法将安全级别转换为整数: {security_level}，使用默认值0")
                                    security_level = 0
                            
                            item["snmpv3_securitylevel"] = security_level
                            logger.info(f"设置SNMPv3安全级别: {security_level}")
                        
                        # 根据安全级别设置不同的参数
                        if security_level in [1, 2]:  # authNoPriv或authPriv
                            # 认证协议
                            auth_protocol = self.snmpv3_auth_protocol_combo.currentData()
                            if auth_protocol:
                                # API期望的值是数字，需要转换
                                auth_protocol_value = auth_protocol
                                if isinstance(auth_protocol, str):
                                    if auth_protocol.lower() == "md5":
                                        auth_protocol_value = "0"
                                    elif auth_protocol.lower() == "sha":
                                        auth_protocol_value = "1"
                                
                                item["snmpv3_authprotocol"] = auth_protocol_value
                                logger.info(f"设置SNMPv3认证协议: {auth_protocol} (API值: {auth_protocol_value})")
                            
                            # 认证密码
                            auth_passphrase = self.snmpv3_auth_passphrase_edit.text()
                            if auth_passphrase:
                                item["snmpv3_authpassphrase"] = auth_passphrase
                                logger.info(f"设置SNMPv3认证密码: {auth_passphrase}")  # 不再隐藏密码
                        
                        # 如果安全级别要求加密 (authPriv)
                        if security_level == 2:
                            # 加密协议
                            priv_protocol = self.snmpv3_priv_protocol_combo.currentData()
                            if priv_protocol:
                                # API期望的值是数字，需要转换
                                priv_protocol_value = priv_protocol
                                if isinstance(priv_protocol, str):
                                    if priv_protocol.lower() == "des":
                                        priv_protocol_value = "0"
                                    elif priv_protocol.lower() == "aes":
                                        priv_protocol_value = "1"
                                
                                item["snmpv3_privprotocol"] = priv_protocol_value
                                logger.info(f"设置SNMPv3加密协议: {priv_protocol} (API值: {priv_protocol_value})")
                            
                            # 加密密码
                            priv_passphrase = self.snmpv3_priv_passphrase_edit.text()
                            if priv_passphrase:
                                item["snmpv3_privpassphrase"] = priv_passphrase
                                logger.info(f"设置SNMPv3加密密码: {priv_passphrase}")  # 不再隐藏密码
                            
                            logger.info(f"SNMPv3最终参数: {item}")
                    else:
                        # 如果不是SNMPv3，添加SNMP社区
                        community = self.community_edit.text() or "public"
                        item["snmp_community"] = community
                        logger.info(f"设置SNMP社区: {community}")
                
                # 设置应用集
                if self.applications_edit.text():
                    applications = [app.strip() for app in self.applications_edit.text().split(",")]
                    if applications:
                        item["applications"] = applications
                
                # 添加到要创建的项列表
                items.append(item)
            
            # 如果没有有效项，显示警告并返回
            if not items:
                QMessageBox.warning(self, "创建失败", "没有可用的主机接口来创建监控项")
                return
                
            # 创建监控项
            try:
                # 重新预处理所有监控项，确保接口ID正确设置
                processed_items = []
                for item in items:
                    host_id = item.get("hostid")
                    if host_id:
                        processed_item = self.preprocess_item_params(item, host_id, self.hostid_to_name.get(host_id))
                        processed_items.append(processed_item)
                        logger.info(f"预处理监控项: {processed_item}")
                    else:
                        logger.warning(f"跳过没有hostid的监控项: {item}")
                
                # 使用处理后的监控项列表
                items = processed_items
                
                # 记录完整的API调用参数
                logger.debug(f"监控项创建参数列表: {items}")
                
                # 检查是否所有监控项都有接口ID
                for i, item in enumerate(items):
                    if "interfaceid" not in item:
                        logger.error(f"错误：第{i+1}个监控项缺少接口ID，无法创建")
                
                # 逐个创建监控项，而不是批量创建
                successful_items = 0
                failed_items = 0
                
                for i, item in enumerate(items):
                    try:
                        # 直接调用API创建单个监控项（不使用items包装）
                        logger.debug(f"创建第{i+1}个监控项: {item}")
                        result = self.api._call("item.create", item)  # 直接传递item对象，不使用{"items": [item]}
                        
                        # 记录API返回结果
                        logger.debug(f"第{i+1}个监控项创建结果: {result}")
                        
                        if result and "itemids" in result:
                            successful_items += 1
                        else:
                            failed_items += 1
                            logger.error(f"创建第{i+1}个监控项失败，API返回: {result}")
                    except Exception as e:
                        failed_items += 1
                        logger.error(f"创建第{i+1}个监控项时发生异常: {str(e)}")
                
                # 显示结果
                if successful_items > 0:
                    QMessageBox.information(
                        self,
                        "创建完成",
                        f"成功创建 {successful_items} 个监控项" + 
                        (f"\n{failed_items} 个监控项创建失败" if failed_items > 0 else "")
                    )
                    
                    # 关闭对话框
                    super().accept()  # 关闭对话框
                else:
                    QMessageBox.warning(
                        self,
                        "创建失败",
                        f"所有 {len(items)} 个监控项创建失败"
                    )
                    logger.error(f"没有成功创建任何监控项")
            except Exception as e:
                QMessageBox.critical(
                    self,
                    "创建错误",
                    f"创建监控项时发生错误: {str(e)}"
                )
                logger.error(f"创建监控项时发生异常: {str(e)}")
                
        except Exception as e:
            logger.error(f"监控项创建对话框accept方法错误: {str(e)}")
            QMessageBox.critical(self, "错误", f"创建监控项时发生错误: {str(e)}") 

    def preprocess_item_params(self, item_params, host_id, host_name=None):
        """预处理监控项参数，确保添加所有必要字段"""
        # 确保类型字段存在且为整数
        if "type" not in item_params or item_params["type"] is None:
            logger.warning(f"预处理：监控项缺少type参数，设置默认值0")
            item_params["type"] = 0
        elif isinstance(item_params["type"], str):
            try:
                item_params["type"] = int(item_params["type"])
                logger.warning(f"预处理：监控项的type参数转换为整数: {item_params['type']}")
            except ValueError:
                logger.warning(f"预处理：监控项的type参数无法转换为整数，设置为默认值0")
                item_params["type"] = 0
        
        # 检查主机是否存在接口，并获取接口信息
        try:
            # 获取主机的所有接口
            all_interfaces = self.api._call("hostinterface.get", {
                "hostids": [host_id],
                "output": ["interfaceid", "type", "ip", "port", "main", "details"]
            })
            
            logger.info(f"预处理：主机 {host_name or host_id} 有 {len(all_interfaces) if all_interfaces else 0} 个接口")
            
            # 记录所有接口信息用于调试
            for i, interface in enumerate(all_interfaces or []):
                logger.info(f"预处理：接口 {i+1}: ID={interface.get('interfaceid')}, 类型={interface.get('type')}, IP={interface.get('ip')}, 端口={interface.get('port')}")
            
            # 首先尝试找到与监控项类型匹配的接口
            matching_interface = None
            item_type = item_params.get("type", 0)
            
            # 监控项类型到接口类型的映射
            type_to_interface = {
                0: "1",   # Zabbix Agent -> Agent接口
                1: "1",   # Zabbix Agent (active) -> Agent接口
                2: "1",   # Simple check -> Agent接口
                3: "1",   # Zabbix internal -> Agent接口
                5: "1",   # Zabbix internal -> Agent接口
                7: "1",   # Zabbix agent (active) -> Agent接口
                10: "1",  # External check -> Agent接口
                11: "1",  # Database monitor -> Agent接口
                12: "3",  # IPMI agent -> IPMI接口
                13: "1",  # SSH agent -> Agent接口
                14: "1",  # TELNET agent -> Agent接口
                15: "0",  # Calculated -> 不需要接口
                16: "4",  # JMX agent -> JMX接口
                17: "2",  # SNMP trap -> SNMP接口
                18: "0",  # Dependent item -> 不需要接口
                19: "1",  # HTTP agent -> Agent接口
                20: "2",  # SNMP agent -> SNMP接口
                21: "0",  # Script -> 不需要接口
            }
            
            # 查找与监控项类型匹配的接口类型
            target_interface_type = type_to_interface.get(item_type)
            
            # 如果是不需要接口的类型，直接返回
            if target_interface_type == "0":
                logger.info(f"预处理：监控项类型 {item_type} 不需要接口")
                if "interfaceid" in item_params:
                    del item_params["interfaceid"]
                return item_params
            
            # 查找匹配的接口
            if target_interface_type:
                for interface in all_interfaces or []:
                    if interface.get("type") == target_interface_type:
                        matching_interface = interface
                        logger.info(f"预处理：找到匹配的接口 ID={interface.get('interfaceid')}, 类型={interface.get('type')}")
                        break
            
            # 如果没有找到匹配接口，使用主接口（仅对于需要Agent接口的类型）
            if not matching_interface and target_interface_type == "1":
                for interface in all_interfaces or []:
                    if interface.get("main") == "1" and interface.get("type") == "1":
                        matching_interface = interface
                        logger.info(f"预处理：找到主Agent接口 ID={interface.get('interfaceid')}, 类型={interface.get('type')}")
                        break
            
            # 如果找到了接口，设置interfaceid
            if matching_interface:
                interface_id = matching_interface.get("interfaceid")
                if interface_id:
                    item_params["interfaceid"] = interface_id
                    logger.info(f"预处理：为主机ID {host_id} 添加接口ID: {interface_id}")
                else:
                    logger.warning(f"预处理：找到接口但没有接口ID (主机ID: {host_id})")
            else:
                logger.warning(f"预处理：主机 {host_name or host_id} 没有匹配的接口类型 {target_interface_type}")
                
            # 如果是SNMP类型的监控项，并且找到了SNMP接口，复制SNMP配置
            if item_type in [20, 17] and matching_interface and matching_interface.get("type") == "2":
                # 处理SNMP配置...（保持原有的SNMP配置处理代码不变）
                # 仅当监控项参数中没有指定时，才从接口复制社区和端口
                if "snmp_community" not in item_params and matching_interface.get("details"):
                    try:
                        # 解析details字段
                        details = matching_interface.get("details", "{}")
                        if isinstance(details, str):
                            details = json.loads(details)
                        
                        # 复制SNMP社区
                        if "community" in details and details["community"]:
                            item_params["snmp_community"] = details["community"]
                            logger.info(f"预处理：从接口获取SNMP社区: {item_params['snmp_community']}")
                    except Exception as e:
                        logger.warning(f"预处理：解析SNMP详情时出错: {e}")
                
                # 复制端口（如果未在监控项中指定）
                if "port" not in item_params and matching_interface.get("port"):
                    item_params["port"] = matching_interface.get("port")
                    logger.info(f"预处理：从接口获取端口: {item_params['port']}")
                
                # 处理SNMPv3参数
                try:
                    # 解析details字段获取SNMPv3参数
                    details = matching_interface.get("details", "{}")
                    if isinstance(details, str):
                        details = json.loads(details)
                    
                    # 检查是否是SNMPv3
                    if "version" in details and details["version"] == "3":
                        logger.info("预处理：检测到SNMPv3接口")
                        
                        # 复制SNMPv3参数（如果未在监控项中指定）
                        snmpv3_params = {
                            "securityname": "snmpv3_securityname",
                            "securitylevel": "snmpv3_securitylevel",
                            "authprotocol": "snmpv3_authprotocol",
                            "authpassphrase": "snmpv3_authpassphrase",
                            "privprotocol": "snmpv3_privprotocol", 
                            "privpassphrase": "snmpv3_privpassphrase"
                        }
                        
                        for src_key, dst_key in snmpv3_params.items():
                            if dst_key not in item_params and src_key in details and details[src_key]:
                                item_params[dst_key] = details[src_key]
                                if "passphrase" in dst_key:
                                    logger.info(f"预处理：从接口获取SNMPv3参数: {dst_key}=***")
                                else:
                                    logger.info(f"预处理：从接口获取SNMPv3参数: {dst_key}={details[src_key]}")
                except Exception as e:
                    logger.warning(f"预处理：处理SNMPv3参数时出错: {e}")
            else:
                logger.warning(f"预处理：主机 {host_name or host_id} 没有可用接口")
                
            # 根据接口类型自动调整监控项类型（如果设置为0且是SNMP接口）
            if item_params.get("type") == 0 and matching_interface and matching_interface.get("type") == "2":
                item_params["type"] = 20  # 设置为SNMP agent
                logger.info(f"预处理：检测到SNMP接口，自动将监控项类型调整为SNMP agent (20)")
        
        except Exception as e:
            logger.error(f"预处理：获取主机接口时出错: {e}")
            import traceback
            logger.error(f"预处理：错误详情: {traceback.format_exc()}")
        
        return item_params

    def get_selected_hosts(self):
        """获取表格中所有主机信息"""
        selected_hosts = []
        
        # 获取所有行
        total_rows = self.host_table.rowCount()
        logger.info(f"表格中共有 {total_rows} 行主机")
        
        for row in range(total_rows):
            try:
                # 获取主机ID
                hostid_item = self.host_table.item(row, 0)
                if not hostid_item:
                    continue
                    
                hostid = hostid_item.text()
                
                # 获取主机名称
                hostname_item = self.host_table.item(row, 2)
                hostname = hostname_item.text() if hostname_item else ""
                
                # 获取可见名称
                visible_name_item = self.host_table.item(row, 3)
                visible_name = visible_name_item.text() if visible_name_item else ""
                
                # 获取端口
                port_item = self.host_table.item(row, 4)
                port = port_item.text() if port_item else ""
                
                # 构建主机信息字典
                host_info = {
                    "hostid": hostid,
                    "host": hostname,
                    "name": visible_name,
                    "port": port
                }
                
                # 添加到主机列表
                selected_hosts.append(host_info)
                logger.info(f"添加主机: {host_info}")
                
            except Exception as e:
                logger.error(f"处理第{row}行主机信息时出错: {str(e)}")
                continue
        
        logger.info(f"共获取到 {len(selected_hosts)} 个主机")
        return selected_hosts